import qs from 'qs'
import * as auth from 'auth-provider'
import { useAuth } from 'context/auth-context'
import { useCallback } from 'react'

const apiUrl = process.env.REACT_APP_API_URL // 获取api地址
interface Config extends RequestInit {
  token?: string
  data?: object
}
// 二次封装 fetch
export const http = async (
  endpoint: string, // 请求的路径
  {
    data, // 请求的参数
    token, // token
    headers, // 请求头
    ...customConfig // 自定义配置
  }: Config = {}
) => {
  // 默认配置
  const config = {
    method: 'GET',
    headers: {
      Authorization: token ? `Bearer ${token}` : '', // 把token放到请求头中
      'Content-Type': data ? 'application/json' : '' // 如果请求有参数，把Content-Type设置为application/json
    },
    ...customConfig
  }
  // toUpperCase() 方法用于将字符串转换为大写并返回
  if (config.method.toUpperCase() === 'GET') {
    endpoint += `?${qs.stringify(data)}` // 拼接参数
  } else {
    config.body = JSON.stringify(data || {}) // 把参数转为json字符串
  }
  // axios 和 fetch 的表现不一样，axios可以直接在返回状态不为2xx的时候抛出异常
  return window
    .fetch(`${apiUrl}/${endpoint}`, config)
    .then(async (response) => {
      // 如果状态码是401，表示未授权，需要重新登录
      if (response.status === 401) {
        await auth.logout() // 调用auth-provider中的logout方法
        window.location.reload() // 刷新页面
        return Promise.reject({ message: '请重新登录' })
      }
      const data = await response.json() // 把返回的数据转为json格式
      if (response.ok) {
        return data
      } else {
        return Promise.reject(data)
      }
    })
}

// useHttp 是一个高阶函数，返回一个函数，这个函数会自动把当前用户的token带上
export const useHttp = () => {
  const { user } = useAuth() // 获取当前用户信息
  // useCallback 返回一个 memoized（记忆）的回调函数
  return useCallback(
    // Parameters 提取函数的入参类型，返回一个元组类型
    (...[endpoint, config]: Parameters<typeof http>) => {
      // fetch 请求
      return http(endpoint, {
        ...config,
        token: user?.token // 自动把当前用户的token带上
      })
    },
    [user?.token]
  )
}
